import type { Ref } from 'vue';
import type { GetFileChunkWithSHA256 } from '@/util/file_type';
import CryptoJS from 'crypto-js';

export async function GetFileChunkWithSHA256(
  file: File,
  chunkSize: number,
  processVal: Ref<number>
): Promise<GetFileChunkWithSHA256> {
  const result: GetFileChunkWithSHA256 = {
    FileSize: 0,
    FileSha256: '',
    FileChunkHash: new Map<number, string>(),
    FileChunk: []
  };

  const fileChunkTotal: number = Math.ceil(file.size / chunkSize);

  const sha256Obj = CryptoJS.algo.SHA256.create();

  result.FileSize = file.size;

  let start = 0; // 分片开始位置
  let end = 0;
  let index: number = 1;
  while (start < result.FileSize) {
    end = start + chunkSize;
    if (end > result.FileSize) {
      end = result.FileSize;
    }

    // 单个分片
    const chunk: Blob = file.slice(start, end);
    // 存储分片
    result.FileChunk.push(chunk);

    // 计算单个 chunk 的哈希值
    await new Promise((resolve, reject) => {
      const fileReader = new FileReader();
      fileReader.onload = () => {
        try {
          // chunk 数据转 WordArray
          const arrayBuffer = fileReader.result as ArrayBuffer;
          const wordArray = CryptoJS.lib.WordArray.create(arrayBuffer);
          sha256Obj.update(wordArray); // 文件总体hash更新
          const chunkMD5Obj = CryptoJS.algo.MD5.create(); // 创建分片的 md5 对象
          chunkMD5Obj.update(wordArray); // 分片的 md5 更新
          const chunkHashVal: string = chunkMD5Obj.finalize().toString(CryptoJS.enc.Hex); // 分片的哈希值
          result.FileChunkHash.set(index, chunkHashVal); // 保存分片哈希结果
          resolve(null);
        } catch (error) {
          console.log('计算分片哈希值失败 ', error);
          reject(error);
        }
      };
      fileReader.onerror = (event) => {
        reject(new Error(`文件分片读取失败: ${(event.target as any).error}`));
      };

      // 读取文件分片
      fileReader.readAsArrayBuffer(chunk);
    });
    processVal.value = parseFloat((index / fileChunkTotal).toFixed(2));
    index++;
    start = end;
  }
  // 文件总体哈希值计算
  result.FileSha256 = sha256Obj.finalize().toString(CryptoJS.enc.Hex);
  return result;
}
